#include "BufferWrapper.h"


BufferWrapper::BufferWrapper() : m_Buffer(0)
{
}

BufferWrapper::~BufferWrapper()
{
	free(); 
}

void BufferWrapper::init(size_t capacity) {
	assert(isFree() && "Buffer is not free");

	m_MagicNumbers.resize(capacity,0);	
	m_IdToPointer.resize(capacity,0);

	for(dataId_t i=0; i<capacity; ++i) {
		m_FreeIds.push_back(i);
	}
}

void BufferWrapper::free() {
	if(isFree())
		return;

	switch(m_Type) {
	case poolBuffer:
		delete m_PoolBuffer;
		break;
	case stackBuffer:
		delete m_StackBuffer;
		break;
	case managedPoolBuffer:
		m_ManagedBuffer->FreePools();
		delete m_ManagedBuffer;
		break;
	}

	m_Buffer = 0;
	m_MagicNumbers.clear();
	m_IdToPointer.clear();
	m_FreeIds.clear();
}

void BufferWrapper::createPoolBuffer(size_t elementSize, size_t capacity) {
	init(capacity);

	m_Type = poolBuffer;
	m_PoolBuffer = new PoolMemoryManager(elementSize, capacity);
}

void BufferWrapper::createStackBuffer(size_t byteAlignment, size_t capacity) {
	init(capacity);

	m_Type = stackBuffer;
	m_StackBuffer = new StackMemorySystem(capacity*byteAlignment, byteAlignment);
}

void BufferWrapper::createManagedBuffer() {
	init(0);
	m_Type = managedPoolBuffer;
	m_ManagedBuffer = new PoolGroupManager();
}

void BufferWrapper::addPoolToManage(size_t elementSize, size_t capacity) {
	assert(m_Type == managedPoolBuffer && "Buffer is not a Managed Pool");

	unsigned int currentCapacity = m_IdToPointer.size();
	unsigned int newCapacity = currentCapacity + capacity;

	m_ManagedBuffer->AddNewPool(elementSize, capacity);

	// add new indices
	m_MagicNumbers.resize(newCapacity, 0);	
	m_IdToPointer.resize(newCapacity, 0);

	for(dataId_t i=currentCapacity; i<newCapacity; ++i) {
		m_FreeIds.push_back(i);
	}
}

void BufferWrapper::release(dataId_t id, unsigned int magicNumber) {
	assert(!isFree() && "Release from a free buffer");
	assert(id < m_IdToPointer.size() && "Handle id overflow");
	assert(m_MagicNumbers[id] == magicNumber && "Incorrect magic number");

	void* pointer = m_IdToPointer[id];

	switch(m_Type) {
	case poolBuffer:
		m_PoolBuffer->Delete(pointer);
		break;
	case stackBuffer:
		Marker_t marker;
		marker.nHeapNum = StackMemorySystem::LOWER;
		marker.pMarker = static_cast<unsigned char*>(pointer);
		m_StackBuffer->freeToMarker(marker);

		for(dataId_t i = m_FreeIds.front() - 1; i>id; --i) {
			m_FreeIds.push_front(i);
			m_IdToPointer[i] = 0;
			m_MagicNumbers[i] = 0;
		}

		break;
	case managedPoolBuffer:
		m_ManagedBuffer->Delete(pointer);
		break;
	}

	m_FreeIds.push_front(id);
	m_IdToPointer[id] = 0;
	m_MagicNumbers[id] = 0;
}